﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using Tamir.SharpSsh.jsch;
using System.IO;

namespace GeoSwarm_Editor
{
    public partial class LevelTransfer : Form
    {

        private Main main;
        private SSH ssh;
        private StatusDialog statusDialog;
        private string upload_tempLevelFile;
        private string upload_destDir;
        private string upload_destFile;

        public LevelTransfer(Main main)
        {
            this.main = main;
            statusDialog = new StatusDialog(this, "Working...", "Working...");
            InitializeComponent();
            main.Hide();
            this.Show();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void button_Connect_Click(object sender, EventArgs e)
        {
            // Checks that IP is entered
            if (ip_1.Text.Length < 1 || ip_2.Text.Length < 1 || ip_3.Text.Length < 1 || ip_4.Text.Length < 1)
            {
                MessageBox.Show("Invalid IP address entered.", "Error");
                return;
            }
            // Check that root password is entered
            if (control_DevicePassword.Text.Length < 1)
            {
                MessageBox.Show("You must enter your device's root password.", "Error");
                return;
            }
            statusDialog.ProgBarStyle = ProgressBarStyle.Marquee;
            statusDialog.UpdateStatus("Attempting to connect...");
            statusDialog.DialogTitle = "Connecting";
            statusDialog.Show();
            this.Enabled = false;
            Thread connectThread = new Thread(new ThreadStart(Connect));
            connectThread.Start();
        }

        private void statusCloseProgEvent()
        {
            statusDialog.CloseProg();
        }

        private void Connect()
        {
            string msg = string.Empty, title = string.Empty;
            bool caught = false;
            try
            {
                ssh = new SSH(statusDialog);
                ssh.IP = ip_1.Text + "." + ip_2.Text + "." + ip_3.Text + "." + ip_4.Text;
                ssh.Password = control_DevicePassword.Text;
                ssh.Connect();
                ConnectedUIChange();
                PopulateDirectories();
                StatusClose();
            }
            catch (JSchException)
            {
                msg = "Could not connect to " + ssh.IP + ":22. Check that you entered your root password correctly, that the device is switched on, that OpenSSH is running, and that this computer and your device are connected to the network. If the problem persists, check your firewall or check that OpenSSH on your device is configured to listen on port 22.";
                title = "Connection Error";
                caught = true;
            }
            catch (Exception ex)
            {
                msg = "An Exception Occured While Connecting: " + ex.Message;
                title = "Exception Handler";
                caught = true;
            }
            finally
            {
                if (caught)
                {
                    StatusClose();
                    MessageBox.Show(msg, title);
                    DisconnectSSH();
                }
            }
        }

        private void AutoDetect()
        {
            try
            {
                bool found = false;
                foreach (string dir in control_GDSdir.Items)
                {
                    ArrayList contents = ssh.ListDir("/private/var/mobile/Applications/" + dir);
                    if (contents.Contains("geoDefenseSwarm.app"))
                    {
                        SetAutoDetectDir(dir);
                        found = true;
                        break;
                    }
                }
                StatusClose();
                if (!found)
                    MessageBox.Show("The geoDefense Swarm directory couldn't be identified. Are you sure you have it installed?", "Oopsy");
            }
            catch (IOException)
            {
                StatusClose();
                MessageBox.Show("An error occured while auto-detecting: the connection was terminated at the remote end.", "Exception Handler");
                DisconnectSSH();
            }
            catch (Exception ex)
            {
                StatusClose();
                MessageBox.Show("An exception occured while auto-detecting: " + ex.Message, "Exception Handler");
                DisconnectSSH();
            }
        }

        private delegate void SetAutoDetectDirCallback(string dir);

        private void SetAutoDetectDir(string dir)
        {
            if (this.InvokeRequired)
            {
                SetAutoDetectDirCallback d = new SetAutoDetectDirCallback(SetAutoDetectDir);
                this.Invoke(d, dir);
            }
            else
            {
                control_GDSdir.SelectedIndex = control_GDSdir.Items.IndexOf(dir);
            }
        }

        private delegate void StatusCloseCallback();

        private void StatusClose()
        {
            if (this.InvokeRequired)
            {
                StatusCloseCallback d = new StatusCloseCallback(StatusClose);
                this.Invoke(d);
            }
            else
            {
                statusDialog.CloseProg();
            }
        }

        private delegate void ConnectedUIChangeCallback();

        private void ConnectedUIChange()
        {
            if (this.InvokeRequired)
            {
                ConnectedUIChangeCallback d = new ConnectedUIChangeCallback(ConnectedUIChange);
                this.Invoke(d);
            }
            else
            {
                button_Connect.Enabled = false;
                button_Disconnect.Enabled = true;
                groupBox2.Enabled = true;
                statusDialog.UpdateStatus("Retrieving Application Dir List...");
            }
        }

        private delegate void PopulateDirectoriesCallback();

        private void PopulateDirectories()
        {
            if (this.InvokeRequired)
            {
                PopulateDirectoriesCallback d = new PopulateDirectoriesCallback(PopulateDirectories);
                this.Invoke(d);
            }
            else
            {
                try
                {
                    ArrayList applicationsDirContents = ssh.ListDir("/private/var/mobile/Applications");
                    foreach (string dirName in applicationsDirContents)
                    {
                        if (dirName.Length > 5)
                            control_GDSdir.Items.Add(dirName);
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Your applications directory could not be listed. Are you sure you're connecting to an iOS device?");
                    DisconnectSSH();
                }
            }
        }

        private void button_Disconnect_Click(object sender, EventArgs e)
        {
            DisconnectSSH();
            ssh = null;
        }

        private void LevelTransfer_FormClosing(object sender, FormClosingEventArgs e)
        {
            DisconnectSSH();
            main.Show();
        }

        private delegate void DisconnectSSHCallback();

        private void DisconnectSSH()
        {
            try
            {
                if(ssh != null)
                    ssh.Disconnect();
                if (this.InvokeRequired)
                {
                    DisconnectSSHCallback d = new DisconnectSSHCallback(DisconnectSSH);
                    this.Invoke(d);
                }
                else
                {
                    button_Disconnect.Enabled = false;
                    button_Connect.Enabled = true;
                    groupBox2.Enabled = false;
                    button_StartTransfer.Enabled = false;
                    control_GDSdir.Items.Clear();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured while trying to disconnect.", "Exception Handler");
            }
        }

        private void button_AutoDetect_Click(object sender, EventArgs e)
        {
            statusDialog.ProgBarStyle = ProgressBarStyle.Marquee;
            statusDialog.UpdateStatus("Attempting to auto-detect directory...");
            statusDialog.DialogTitle = "Auto-Detection";
            statusDialog.Show();
            this.Enabled = false;
            Thread detectThread = new Thread(new ThreadStart(AutoDetect));
            detectThread.Start();
        }

        private void button_StartTransfer_Click(object sender, EventArgs e)
        {
            ArrayList destDirContents;
            this.Enabled = false;
            this.upload_destDir = "/var/mobile/Applications/" + control_GDSdir.SelectedItem.ToString() + "/geoDefenseSwarm.app";
            try
            {
                destDirContents = ssh.ListDir(upload_destDir);
            }
            catch (SftpException)
            {
                MessageBox.Show("There was a problem listing the contents of your geoDefenseSwarm.app directory.");
                this.Enabled = true;
                return;
            }
            if(destDirContents.Contains(control_Filename.Text))
            {
                DialogResult result = MessageBox.Show("The destination file already exists. Do you want to replace it?", "File Exists", MessageBoxButtons.YesNo);
                if (result == DialogResult.No)
                {
                    this.Enabled = true;
                    return;
                }
            }
            string tempDir = System.IO.Path.GetTempPath();
            this.upload_tempLevelFile = tempDir + "/" + control_Filename.Text;
            this.upload_destFile = control_Filename.Text;
            main.SaveLevelProg(upload_tempLevelFile);
            statusDialog.ProgBarStyle = ProgressBarStyle.Continuous;
            statusDialog.UpdateStatus("Uploading level to device...");
            statusDialog.DialogTitle = "Upload Progress";
            statusDialog.UpdatePercentDone(0);
            statusDialog.Show();
            Thread uploadThread = new Thread(new ThreadStart(UploadLevel));
            uploadThread.Start();
        }

        private void UploadLevel()
        {
            try
            {
                ssh.Transfer(upload_tempLevelFile, upload_destDir + "/" + upload_destFile);
            }
            catch (Exception ex)
            {
                MessageBox.Show("The following exception was thrown while uploading the level to your device: " + ex.Message, "Exception Handler");
            }
            StatusClose();
        }

        private void control_GDSdir_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (control_GDSdir.SelectedIndex >= 0)
                button_StartTransfer.Enabled = true;
            else
                button_StartTransfer.Enabled = false;
        }
    }
}